home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / drdobbs / 1989 / 05 / smlter.asc < prev    next >
Text File  |  1989-05-12  |  28KB  |  895 lines

  1. _C Programming Column_
  2. by Al Stevens
  3.  
  4. [LISTING ONE]
  5.  
  6.  
  7. /* ---------------- interp.h -------------------- */
  8. #define TOKBUFSIZE 4096     /* token buffer size           */
  9. #define MAXSYMBOLS  100     /* maximum symbols in table    */
  10. #define MAXSTRINGS   50     /* maximum strings in arrays   */
  11. #define MAXPARAMS    10     /* maximum parameters in calls */
  12. /* ----------- error codes ----------------- */
  13. enum errs {EARLYEOF,UNRECOGNIZED,DUPL_DECLARE,TABLEOVERFLOW,
  14.            OMERR,UNDECLARED,SYNTAX,BRACERR,PARENERR,MISSING,
  15.            NOTFUNC,BREAKERR,OUTOFPLACE,TOOMANYSTRINGS,BUFFULL,
  16.            DIVIDEERR};
  17. /* ------- intrinsic function table -------- */
  18. typedef struct {
  19.     char *fname;
  20.     int (*fn)(int *);
  21. } INTRINSIC;
  22. /* -------- symbol table ------------ */
  23. typedef struct {
  24.     char *symbol;   /* points to symbol name                 */
  25.     char *location; /* points to function code (NULL if int) */
  26.     char **tblloc;  /* points to table array (NULL if func)  */
  27.     int ival;       /* value of integer                      */
  28. } SYMBOL;
  29. /* ------- function prototypes -------- */
  30. void loadsource(void);
  31. int function(char *, SYMBOL *);
  32. #define interpret() function("main\0();", symtop);
  33. /* ------ functions provided by the shell -------- */
  34. int getsource(void);
  35. void ungetsource(int);
  36. void sierror(enum errs, char *, int);
  37. /* -------- the compiled (interpretable) S source -------- */
  38. extern SYMBOL globals[];
  39. extern char *tokenbf;
  40. extern char *strings[];
  41. extern SYMBOL *symtop;
  42.  
  43.  
  44. [LISTING TWO]
  45.  
  46. /* ----------- interp.c ----------- */
  47. #include <stdio.h>
  48. #include <conio.h>
  49. #include <string.h>
  50. #include <stdlib.h>
  51. #include <ctype.h>
  52. #include <process.h>
  53. #include "interp.h"
  54. #define TRUE 1
  55. #define FALSE 0
  56. /* --------- the compiled (interpretable) S source ---------- */
  57. SYMBOL globals[MAXSYMBOLS]; /* function/variable symbol table */
  58. char *tokenbf = NULL;       /* compiled token buffer          */
  59. char *strings[MAXSTRINGS];  /* char *[] string arrays         */
  60. SYMBOL *symtop;             /* top of symbol table            */
  61. /* ---------- the external intrinsic functions ----------- */
  62. extern INTRINSIC *infs;     /* initialized by the SI shell */
  63. /* ------ function macros ------------ */
  64. #define bypass() tptr+=strlen(tptr)+1
  65. #define isletter(c) (isalpha(c)||isdigit(c)||c =='_')
  66. #define iswhite(c) (c==' '||c=='\t')
  67. /* ---- function prototypes ----- */
  68. static void linker(void);
  69. static int gettoken(void);
  70. static int getok(void);
  71. static int iskeyword(void);
  72. static int isident(void);
  73. static int istoken(void);
  74. static int getword(void);
  75. static int getcx(void);
  76. static void compound_statement(SYMBOL *);
  77. static void statement(SYMBOL *);
  78. static void statements(SYMBOL *);
  79. static void skip_statements(SYMBOL *);
  80. static void addsymbol(SYMBOL *, char *, char *, char **);
  81. static SYMBOL *findsymbol(SYMBOL *, char *, SYMBOL *);
  82. static SYMBOL *ifsymbol(SYMBOL *, char *, SYMBOL *);
  83. static void freesymbols(SYMBOL *);
  84. static void error(enum errs, char *);
  85. static int  iftoken(int);
  86. static void skippair(int, int);
  87. static void needtoken(int);
  88. static int  iftoken(int);
  89. static int  nexttoken(void);
  90. static int  expression(SYMBOL *);
  91. static int escseq(void);
  92. /* --------------- tokens ------------------ */
  93. #define AUTOINC    'P'
  94. #define AUTODEC    'D'
  95. #define EQUALTO    'E'
  96. #define NOTEQUAL   'N'
  97. #define GE         'G'
  98. #define LE         'L'
  99. #define IF         'f'
  100. #define ELSE       'e'
  101. #define WHILE      'w'
  102. #define FOR        'F'
  103. #define CHAR       'c'
  104. #define INT        'i'
  105. #define STRING     's'
  106. #define COMMENT1   '/'
  107. #define COMMENT2   '*'
  108. #define POINTER    '*'
  109. #define PLUS       '+'
  110. #define MINUS      '-'
  111. #define MULTIPLY   '*'
  112. #define DIVIDE     '/'
  113. #define EQUAL      '='
  114. #define LESS       '<'
  115. #define GREATER    '>'
  116. #define NOT        '!'
  117. #define LPAREN     '('
  118. #define RPAREN     ')'
  119. #define LBRACE     '{'
  120. #define RBRACE     '}'
  121. #define LBRACKET   '['
  122. #define RBRACKET   ']'
  123. #define COMMA      ','
  124. #define AND        '&'
  125. #define ADDRESS    '@'
  126. #define OR         '|'
  127. #define QUOTES     '"'
  128. #define QUOTE      '\''
  129. #define UNDERSCORE '_'
  130. #define SEMICOLON  ';'
  131. #define IDENT      'I'
  132. #define CONSTANT   'C'
  133. #define LINENO     127
  134. #define RETURN     'r'
  135. #define BREAK      'b'
  136. /* -------- table of key words and their tokens --------- */
  137. static struct keywords {
  138.     char *kw;
  139.     int kwtoken;
  140. } kwds[] = {
  141.     "\n",    LINENO,
  142.     "for",   FOR,
  143.     "while", WHILE,
  144.     "if",    IF,
  145.     "else",  ELSE,
  146.     "int",   INT,
  147.     "char",  CHAR,
  148.     "return",RETURN,
  149.     "break", BREAK,
  150.      NULL,   0
  151. };
  152. /* ------------ table of direct translate tokens -------- */
  153. static int tokens[] = {
  154.     COMMA,LBRACE,RBRACE,LPAREN,RPAREN,EQUAL,NOT,POINTER,
  155.     LESS,GREATER,AND,OR,QUOTES,SEMICOLON,LBRACKET,RBRACKET,
  156.     MULTIPLY,DIVIDE,PLUS,MINUS,EOF,LINENO,0
  157. };
  158. /* --------------------- local data ----------------------- */
  159. static char word[81];  /* word space for source parsing     */
  160. static int linenumber; /* current source file line number   */
  161. static int frtn;       /* return value from a function      */
  162. static char *tptr;     /* running token pointer             */
  163. static int stptr;      /* running string allocation offset  */
  164. static int breaking, returning, skipping;
  165. static SYMBOL *endglobals;
  166. /* ----------- lexical scan and call linker ------------ */
  167. void loadsource(void)
  168. {
  169.     int tok = 0;
  170.     if (tokenbf == NULL)
  171.         if ((tokenbf = malloc(TOKBUFSIZE+81)) == NULL)
  172.             error(OMERR, "");
  173.     symtop = symtop ? symtop : globals;
  174.     freesymbols(globals);
  175.     memset(tokenbf, '\0', TOKBUFSIZE+81);
  176.     linenumber = 1;
  177.     tptr = tokenbf;
  178.     while (tok != EOF)  {
  179.         if (tptr >= tokenbf + TOKBUFSIZE)
  180.             error(BUFFULL, "");
  181.         *tptr++ = tok = gettoken();
  182.         switch (tok)    {
  183.             case LINENO:
  184.                 sprintf(tptr, "%03d", linenumber);
  185.                 tptr += 3;
  186.                 break;
  187.             case CONSTANT:
  188.             case IDENT:
  189.             case STRING:
  190.                 strcpy(tptr, word);
  191.                 bypass();
  192.                 break;
  193.             default:
  194.                 break;
  195.         }
  196.     }
  197.     linker();   /* link the external variables and functions */
  198. }
  199. /* -- convert a script program to tokens for interpreter,
  200.         return the next token -------- */
  201. static int gettoken(void)
  202. {
  203.     int tok = getword();
  204.     if (tok == 0)
  205.         if ((tok = iskeyword()) == 0)
  206.             if ((tok = istoken()) == 0)
  207.                 tok = isident();
  208.     if (tok == 0)
  209.         error(UNRECOGNIZED, word);
  210.     return tok;
  211. }
  212. /* ----- test to see if current word is a token ----- */
  213. static int istoken(void)
  214. {
  215.     int *t = tokens, t2;
  216.     while (*t && word[1] == '\0')
  217.         if (*word == *t++)  {
  218.             switch (*word)  {
  219.                 case EOF:
  220.                     break;
  221.                 case AND:
  222.                     if ((t2 = getcx()) != AND)  {
  223.                         *word = ADDRESS;
  224.                         ungetsource(t2);
  225.                     }
  226.                     break;
  227.                 case OR:
  228.                     if (getcx() != OR)
  229.                         error(MISSING, word);
  230.                     break;
  231.                 case PLUS:
  232.                 case MINUS:
  233.                     if ((t2 = getcx()) == *word)
  234.                         *word = *word==PLUS ? AUTOINC : AUTODEC;
  235.                     else
  236.                         ungetsource(t2);
  237.                     break;
  238.                 default:
  239.                     if ((t2 = getcx()) == EQUAL)    {
  240.                         switch (*word)  {
  241.                             case EQUAL:   return EQUALTO;
  242.                             case NOT:     return NOTEQUAL;
  243.                             case LESS:    return LE;
  244.                             case GREATER: return GE;
  245.                             default:      break;
  246.                         }
  247.                     }
  248.                     ungetsource(t2);
  249.                     break;
  250.             }
  251.             return *word;
  252.         }
  253.     return 0;
  254. }
  255. /* -------- test word for a keyword --------- */
  256. static int iskeyword()
  257. {
  258.     struct keywords *k = kwds;
  259.     while (k->kw)
  260.         if (strcmp(k->kw, word) == 0)
  261.             return k->kwtoken;
  262.         else
  263.             k++;
  264.     return 0;
  265. }
  266. /* ------ test for an ident -------- */
  267. static int isident()
  268. {
  269.     char *wd = word;
  270.     int n = 0;
  271.     if (isalpha(*wd) || *wd == UNDERSCORE)
  272.         return IDENT;
  273.     if (strlen(wd) <= 6)    {
  274.         if (strncmp(wd, "0x", 2) == 0)  {
  275.             wd += 2;            /* 0x.... hex constant */
  276.             while (*wd) {
  277.                 n = (n*16)+(isdigit(*wd) ? *wd-'0' :
  278.                     tolower(*wd) - 'a' + 10);
  279.                 wd++;
  280.             }
  281.             sprintf(word,"%d", n); /* converted hex constant */
  282.         }
  283.         else                    /* test for decimal constant */
  284.             while (*wd)
  285.                 if (!isdigit(*wd++))
  286.                     return 0;
  287.         return CONSTANT;
  288.     }
  289.     return 0;
  290. }
  291. /* -------- get the next word from the input stream ------- */
  292. static int getword(void)
  293. {
  294.     char *wd = word;
  295.     int c = ' ', tok = 0;
  296.     while (iswhite(c))                 /* bypass white space */
  297.         c = getok();
  298.     if (c == QUOTE)     {
  299.         tok = CONSTANT;              /* quoted constant ('x') */
  300.         if ((c = getcx()) == '\\')   /* escape sequence (\n)  */
  301.             c = escseq();
  302.         sprintf(word, "%d", c);   /* build the constant value */
  303.         wd += strlen(word);
  304.         if (getcx() != QUOTE)     /* needs the other quote    */
  305.             error(MISSING,"'");
  306.     }
  307.     else if (c == QUOTES)    {
  308.         tok = STRING;                 /* quoted string "abc"  */
  309.         while ((c = getcx()) != QUOTES)
  310.             *wd++ = c == '\\' ? escseq() : c;
  311.     }
  312.     else    {
  313.         *wd++ = c;                  /* 1st char of word */
  314.         while (isletter(c)) {       /* build an ident   */
  315.             c = getok();
  316.             if (isletter(c))
  317.                 *wd++ = c;
  318.             else
  319.                 ungetsource(c);
  320.         }
  321.     }
  322.     *wd = '\0';       /* null terminate the word or token */
  323.     return tok;
  324. }
  325. /* ---- escape sequence in literal constant or string ---- */
  326. static int escseq()
  327. {
  328.     int c = getcx();
  329.     return (c == 'n' ? '\n' :
  330.             c == 't' ? '\t' :
  331.             c == 'f' ? '\f' :
  332.             c == 'a' ? '\a' :
  333.             c == 'b' ? '\b' :
  334.             c == 'r' ? '\r' :
  335.             c == '0' ? '\0' : c);
  336. }
  337. /* ------- get a character from the input stream -------- */
  338. static int getok(void)
  339. {
  340.     int c, c1;
  341.     while ((c = getsource()) == COMMENT1)   {
  342.         if ((c1 = getcx()) != COMMENT2) {       /* comment */
  343.             ungetsource(c1);
  344.             break;
  345.         }
  346.         while (TRUE)    {   /* found comment begin token pair */
  347.             while ((c1 = getcx()) != COMMENT2)
  348.                 ;
  349.             if ((c1 = getcx()) == COMMENT1)
  350.                 break;      /* found comment end token pair */
  351.         }
  352.     }
  353.     if (c == '\n')      /* count source line numbers */
  354.         linenumber++;
  355.     return c;
  356. }
  357. /* ------- read a character from input, error if EOF ------ */
  358. static int getcx(void)
  359. {
  360.     int c;
  361.     if ((c = getsource()) == EOF)
  362.         error(EARLYEOF, "");
  363.     return c;
  364. }
  365. /* --------- build the global symbol table --------- */
  366. static void linker(void)
  367. {
  368.     int tok = 0;
  369.     char *svtptr;
  370.     INTRINSIC *ff = infs;
  371.     tptr = tokenbf;
  372.     /* --- add intrinsic functions to the symbol table --- */
  373.     while (ff->fname)   {
  374.         addsymbol(globals,ff->fname,ff->fname,NULL);
  375.         ff++;
  376.     }
  377.     while (tok != EOF)  {
  378.         switch (tok = nexttoken())  {
  379.             case CHAR:
  380.                 svtptr = tptr;
  381.                 if (iftoken(POINTER))   {
  382.                     needtoken(IDENT);
  383.                     bypass();
  384.                     if (iftoken(LBRACKET))  {
  385.                         tptr = svtptr;
  386.                         nexttoken();
  387.                         nexttoken();
  388.                         addsymbol(globals,tptr,NULL,
  389.                             strings+stptr);
  390.                         bypass();
  391.                         needtoken(LBRACKET);
  392.                         needtoken(RBRACKET);
  393.                         needtoken(EQUAL);
  394.                         needtoken(LBRACE);
  395.                         while (TRUE)    {
  396.                             if (!iftoken(STRING))
  397.                                 break;
  398.                             if (stptr == MAXSTRINGS)
  399.                                 error(TOOMANYSTRINGS, "");
  400.                             strings[stptr++] = tptr;
  401.                             bypass();
  402.                             if (!iftoken(COMMA))
  403.                                 break;
  404.                         }
  405.                         strings[stptr++] = NULL;
  406.                         needtoken(RBRACE);
  407.                         needtoken(SEMICOLON);
  408.                         break;
  409.                     }
  410.                 }
  411.                 tptr = svtptr;
  412.             case INT:
  413.                 while (TRUE)    {
  414.                     if (iftoken(POINTER))
  415.                         ;
  416.                     needtoken(IDENT);
  417.                     addsymbol(globals,tptr,NULL,NULL);
  418.                     bypass();
  419.                     if (iftoken(EQUAL))
  420.                         (symtop-1)->ival=expression(globals);
  421.                     if (!iftoken(COMMA))
  422.                         break;
  423.                 }
  424.                 needtoken(SEMICOLON);
  425.                 break;
  426.             case IDENT:
  427.                 addsymbol(globals, tptr, tptr, NULL);
  428.                 bypass();
  429.                 skippair(LPAREN, RPAREN);
  430.                 skippair(LBRACE, RBRACE);
  431.                 break;
  432.             case EOF:
  433.                 break;
  434.             default:
  435.                 error(OUTOFPLACE, (char *) &tok);
  436.         }
  437.     }
  438.     endglobals = symtop;
  439. }
  440. /* --------- a function is called ---------- */
  441. int function(char *fnc, SYMBOL *sp)
  442. {
  443.     int params[MAXPARAMS+1], p, i;
  444.     INTRINSIC *ff = infs;
  445.     char *savetptr = tptr;
  446.     frtn = 0;
  447.     tptr = fnc;
  448.     bypass();
  449.     needtoken(LPAREN);
  450.     for (p = 0; p < MAXPARAMS; )  { /* scan for parameters   */
  451.         if (iftoken(RPAREN))
  452.             break;
  453.         params[p++]=expression(sp); /* build params */
  454.         if (!iftoken(COMMA))    {   /* into parameter array  */
  455.             needtoken(RPAREN);
  456.             break;
  457.         }
  458.     }
  459.     params[p] = 0;
  460.     while (ff->fname)   {   /* search the intrinsic table */
  461.         if (strcmp(fnc,ff->fname) == 0) {
  462.             frtn = (*ff->fn)(params); /* call intrinsic func */
  463.             tptr = savetptr;
  464.             return frtn;
  465.         }
  466.         ff++;
  467.     }
  468.     if ((tptr=findsymbol(globals,fnc,endglobals)->location)
  469.              == NULL)
  470.         error(NOTFUNC,fnc);  /* function not declared */
  471.     bypass();
  472.     needtoken(LPAREN);
  473.     sp = symtop;
  474.     for (i = 0; i < p; i++) {  /* params into local sym tbl */
  475.         needtoken(IDENT);
  476.         addsymbol(sp,tptr,NULL,NULL);
  477.         (symtop-1)->ival = params[i];
  478.         bypass();
  479.         if (i < p-1)
  480.             needtoken(COMMA);
  481.     }
  482.     needtoken(RPAREN);
  483.     compound_statement(sp);     /* execute the function */
  484.     freesymbols(sp);            /* release the local symbols */
  485.     tptr = savetptr;
  486.     breaking = returning = FALSE;
  487.     return frtn;              /* the function's return value */
  488. }
  489. /* ------- execute one statement or a {} block -------- */
  490. static void statements(SYMBOL *sp)
  491. {
  492.     if (iftoken(LBRACE))    {
  493.         --tptr;
  494.         compound_statement(sp);
  495.     }
  496.     else
  497.         statement(sp);
  498. }
  499. /* -------- execute a {} statement block ----------- */
  500. static void compound_statement(SYMBOL *sp)
  501. {
  502.     char *svtptr = tptr;
  503.     SYMBOL *spp = symtop;
  504.     needtoken(LBRACE);
  505.     while (iftoken(CHAR) || iftoken(INT))   {
  506.         while (TRUE)    {       /* local variables in block */
  507.             if (iftoken(POINTER))
  508.                 ;               /* bypass pointer token(s)  */
  509.             needtoken(IDENT);
  510.             addsymbol(spp,tptr,NULL,NULL);
  511.             bypass();
  512.             if (iftoken(EQUAL))       /* handle assignments */
  513.                 (symtop-1)->ival=expression(sp);
  514.             if (!iftoken(COMMA))
  515.                 break;
  516.         }
  517.         needtoken(SEMICOLON);
  518.     }
  519.     while (!iftoken(RBRACE) && !breaking && !returning)
  520.         statements(sp);
  521.     tptr = svtptr;            /* point to the opening { brace */
  522.     freesymbols(spp);         /* free the local symbols       */
  523.     skippair(LBRACE, RBRACE); /* skip to end of block         */
  524. }
  525. /* --------- execute a single statement ---------- */
  526. static void statement(SYMBOL *sp)
  527. {
  528.     char *svtptr, *fortest, *forloop, *forblock;
  529.     int rtn, tok = nexttoken();
  530.     switch (tok)    {
  531.         case IF:
  532.             needtoken(LPAREN);
  533.             rtn = expression(sp); /* condition being tested */
  534.             needtoken(RPAREN);
  535.             if (rtn)
  536.                 statements(sp);     /* condition is true  */
  537.             else
  538.                 skip_statements(sp); /* condition is false */
  539.             while (iftoken(ELSE))
  540.                 if (rtn)         /* do the reverse for else */
  541.                     skip_statements(sp);
  542.                 else
  543.                     statements(sp);
  544.             break;
  545.         case WHILE:
  546.             rtn = TRUE;
  547.             breaking = returning = FALSE;
  548.             svtptr = tptr;
  549.             while (rtn && !breaking && !returning)  {
  550.                 tptr = svtptr;
  551.                 needtoken(LPAREN);
  552.                 rtn = expression(sp); /* the condition tested */
  553.                 needtoken(RPAREN);
  554.                 if (rtn)
  555.                     statements(sp);      /* true */
  556.                 else
  557.                     skip_statements(sp); /* false */
  558.             }
  559.             breaking = returning = FALSE;
  560.             break;
  561.         case FOR:
  562.             svtptr = tptr;     /* svptr -> 1st ( after for */
  563.             needtoken(LPAREN);
  564.             if (!iftoken(SEMICOLON))    {
  565.                 expression(sp);  /* initial expression */
  566.                 needtoken(SEMICOLON);
  567.             }
  568.             fortest = tptr;   /* fortest -> terminating test */
  569.             tptr = svtptr;
  570.             skippair(LPAREN,RPAREN);
  571.             forblock = tptr;  /* forblock -> block to run */
  572.             tptr = fortest;
  573.             breaking = returning = FALSE;
  574.             while (TRUE)    {
  575.                 if (!iftoken(SEMICOLON))    {
  576.                     if (!expression(sp)) /* terminating test */
  577.                         break;
  578.                     needtoken(SEMICOLON);
  579.                 }
  580.                 forloop = tptr;
  581.                 tptr = forblock;
  582.                 statements(sp);     /* the loop statement(s) */
  583.                 if (breaking || returning)
  584.                     break;
  585.                 tptr = forloop;
  586.                 if (!iftoken(RPAREN))   {
  587.                     expression(sp);  /* the end of loop expr */
  588.                     needtoken(RPAREN);
  589.                 }
  590.                 tptr = fortest;
  591.             }
  592.             tptr = forblock;
  593.             skip_statements(sp);      /* skip past the block */
  594.             breaking = returning = FALSE;
  595.             break;
  596.         case RETURN:
  597.             if (!iftoken(SEMICOLON))    {
  598.                 frtn = expression(sp);
  599.                 needtoken(SEMICOLON);
  600.             }
  601.             returning = !skipping;
  602.             break;
  603.         case BREAK:
  604.             needtoken(SEMICOLON);
  605.             breaking = !skipping;
  606.             break;
  607.         case IDENT:
  608.             --tptr;
  609.             expression(sp);
  610.             needtoken(SEMICOLON);
  611.             break;
  612.         default:
  613.             error(OUTOFPLACE, (char *) &tok);
  614.     }
  615. }
  616. /* -------- bypass statement(s) ------------ */
  617. static void skip_statements(SYMBOL *sp)
  618. {
  619.     skipping++;   /* semaphore that suppresses assignments,  */
  620.     statements(sp);   /* breaks,returns,++,--,function calls */
  621.     --skipping;   /* turn off semaphore                      */
  622. }
  623. /* -------- recursive descent expression analyzer -------- */
  624. static int primary(SYMBOL *sp)
  625. {
  626.     int tok, rtn = 0;
  627.     SYMBOL *spr;
  628.     switch (tok = nexttoken())  {
  629.         case LPAREN:
  630.             rtn = expression(sp);
  631.             needtoken(RPAREN);
  632.             break;
  633.         case NOT:
  634.             rtn = !primary(sp);
  635.             break;
  636.         case CONSTANT:
  637.             rtn = atoi(tptr);
  638.             bypass();
  639.             break;
  640.         case POINTER:
  641.             rtn = *(int *)primary(sp) & 255;
  642.             break;
  643.         case ADDRESS:
  644.         case AUTOINC:
  645.         case AUTODEC:
  646.             needtoken(IDENT);
  647.         case IDENT:
  648.             if ((spr = ifsymbol(sp,tptr,symtop)) == NULL)
  649.                 spr = findsymbol(globals,tptr,endglobals);
  650.             if (spr->location)  {
  651.                 /* ---- this is a function call ---- */
  652.                 if (tok != IDENT)
  653.                     error(OUTOFPLACE, (char *) &tok);
  654.                 rtn = skipping ? 0 : function(tptr,sp);
  655.                 bypass();
  656.                 skippair(LPAREN,RPAREN);
  657.                 break;
  658.             }
  659.             bypass();
  660.             if (spr->tblloc)    {
  661.                 /* ---- this is a table ---- */
  662.                 rtn = (tok == ADDRESS ?
  663.                         (int) (&spr->tblloc) :
  664.                         (int) ( spr->tblloc)   );
  665.                 break;
  666.             }
  667.             if (!skipping && tok == AUTOINC)
  668.                 ++(spr->ival);
  669.             else if (!skipping && tok == AUTODEC)
  670.                 --(spr->ival);
  671.             if (tok != ADDRESS && iftoken(EQUAL))   {
  672.                 rtn = expression(sp);
  673.                 spr->ival = skipping ? spr->ival : rtn;
  674.             }
  675.             rtn = tok == ADDRESS ? (int)&spr->ival : spr->ival;
  676.             if (tok != ADDRESS)
  677.                 if (iftoken(AUTOINC) && !skipping)
  678.                     (spr->ival)++;
  679.                 else if (iftoken(AUTODEC) && !skipping)
  680.                     (spr->ival)--;
  681.             break;
  682.         case STRING:
  683.             rtn = (int) tptr;
  684.             bypass();
  685.             break;
  686.         default:
  687.             error(OUTOFPLACE, (char *) &tok);
  688.     }
  689.     return rtn;
  690. }
  691. static int mult(SYMBOL *sp)
  692. {
  693.     int drtn, rtn = primary(sp);
  694.     while (TRUE)
  695.         if (iftoken(MULTIPLY))
  696.             rtn = (rtn * primary(sp));
  697.         else if (iftoken(DIVIDE))   {
  698.             if ((drtn = primary(sp)) == 0)
  699.                 error(DIVIDEERR, "");
  700.             rtn /= drtn;
  701.         }
  702.         else
  703.             break;
  704.     return rtn;
  705. }
  706. static int plus(SYMBOL *sp)
  707. {
  708.     int rtn = mult(sp);
  709.     while (TRUE)
  710.         if (iftoken(PLUS))
  711.             rtn = (rtn + mult(sp));
  712.         else if (iftoken(MINUS))
  713.             rtn = (rtn - mult(sp));
  714.         else
  715.             break;
  716.     return rtn;
  717. }
  718. static int le(SYMBOL *sp)
  719. {
  720.     int rtn = plus(sp);
  721.     while (TRUE)
  722.         if (iftoken(LE))
  723.             rtn = (rtn <= plus(sp));
  724.         else if (iftoken(GE))
  725.             rtn = (rtn >= plus(sp));
  726.         else if (iftoken(LESS))
  727.             rtn = (rtn < plus(sp));
  728.         else if (iftoken(GREATER))
  729.             rtn = (rtn > plus(sp));
  730.         else
  731.             break;
  732.     return rtn;
  733. }
  734. static int eq(SYMBOL *sp)
  735. {
  736.     int rtn = le(sp);
  737.     while (TRUE)
  738.         if (iftoken(EQUALTO))
  739.             rtn = (rtn == le(sp));
  740.         else if (iftoken(NOTEQUAL))
  741.             rtn = (rtn != le(sp));
  742.         else
  743.             break;
  744.     return rtn;
  745. }
  746. static int and(SYMBOL *sp)
  747. {
  748.     int rtn = eq(sp);
  749.     while (iftoken(AND))
  750.         rtn = (eq(sp) && rtn);
  751.     return rtn;
  752. }
  753. static int expression(SYMBOL *sp)
  754. {
  755.     int rtn = and(sp);
  756.     while (iftoken(OR))
  757.         rtn = (and(sp) || rtn);
  758.     return rtn;
  759. }
  760. /* ----- skip the tokens between a matched pair ----- */
  761. static void skippair(int ltok, int rtok)
  762. {
  763.     int pairct = 0, tok;
  764.     if ((tok = nexttoken()) != ltok)
  765.         error(ltok == LBRACE ? BRACERR : PARENERR, "");
  766.     while (TRUE)    {
  767.         if (tok == ltok)
  768.             pairct++;
  769.         if (tok == rtok)
  770.             if (--pairct == 0)
  771.                 break;
  772.         if ((tok = nexttoken()) == EOF)
  773.             error(ltok == LBRACE ? BRACERR : PARENERR, "");
  774.     }
  775. }
  776. /* ----- a specified token is required next ----- */
  777. static void needtoken(int tk)
  778. {
  779.     if (nexttoken() != tk)
  780.         error(MISSING, (char *) &tk);
  781. }
  782. /* ----- test for a specifed token next in line ----- */
  783. static int iftoken(int tk)
  784. {
  785.     if (nexttoken() == tk)
  786.         return TRUE;
  787.     --tptr;
  788.     return FALSE;
  789. }
  790. /* ----- get the next token from the buffer ----- */
  791. static int nexttoken(void)
  792. {
  793.     while (*tptr == LINENO)
  794.         tptr += 4;
  795.     return *tptr++;
  796. }
  797. /* ------ add a symbol to the symbol table ------------ */
  798. static void
  799. addsymbol(SYMBOL *s,char *sym,char *floc,char **tloc)
  800. {
  801.     if (ifsymbol(s,sym,symtop) != NULL)
  802.         error(DUPL_DECLARE, sym);
  803.     if (symtop == globals + MAXSYMBOLS)
  804.         error(TABLEOVERFLOW, "");
  805.     if ((symtop->symbol = malloc(strlen(sym) + 1)) == NULL)
  806.         error(OMERR, "");
  807.     strcpy(symtop->symbol, sym);
  808.     symtop->location = floc;
  809.     symtop->tblloc = tloc;
  810.     symtop->ival = 0;
  811.     symtop++;
  812. }
  813. /* --------- find a symbol on the symbol table --------- */
  814. static SYMBOL *findsymbol(SYMBOL *s, char *sym, SYMBOL *ends)
  815. {
  816.     if ((s = ifsymbol(s, sym, ends)) == NULL)
  817.         error(UNDECLARED, sym);
  818.     return s;
  819. }
  820. /* -------- test for a symbol on the symbol table ------ */
  821. static SYMBOL *ifsymbol(SYMBOL *s, char *sym, SYMBOL *sp)
  822. {
  823.     while (s < sp--)
  824.         if (strcmp(sym, sp->symbol) == 0)
  825.             return sp;
  826.     return NULL;
  827. }
  828. /* ------- free the symbols from a symbol table ------- */
  829. static void freesymbols(SYMBOL *s)
  830. {
  831.     while (s < symtop)
  832.         free((--symtop)->symbol);
  833. }
  834. /* -------- post an error to the shell ------- */
  835. static void error(enum errs erno, char *s)
  836. {
  837.     while (*tptr != LINENO && tptr > tokenbf)
  838.         --tptr;
  839.     sierror(erno, s, (*tptr == LINENO) ? atoi(tptr+1) : 1);
  840. }
  841.  
  842.  
  843. [LISTING THREE]
  844.  
  845. /* ---------- si.c -------------- */
  846. #include <stdio.h>
  847. #include <conio.h>
  848. #include <stdlib.h>
  849. #include "interp.h"
  850. /* ----------- intrinsic interpreter functions ---------- */
  851. static int iprntf(int *p)           /*   printf   */
  852. {
  853.     printf((char*)p[0],p[1],p[2],p[3],p[4]);
  854.     return 0;
  855. }
  856. static int igtch(int *p)            /*  getchar   */
  857. {
  858.     return putch(getch());
  859. }
  860. static int iptch(int *c)            /*  putchar   */
  861. {
  862.     return putchar(*c);
  863. }
  864. INTRINSIC ffs[] = { "printf",  iprntf,
  865.                     "getchar", igtch,
  866.                     "putchar", iptch,
  867.                      NULL,     NULL      };
  868. extern INTRINSIC *infs = ffs;
  869. /* ---------- error messages ------------- */
  870. char *erm[]={  "Unexpected end of file", "Unrecognized",
  871.                "Duplicate ident",        "Symbol table full",
  872.                "Out of heap memory",     "Undeclared ident",
  873.                "Syntax Error",           "Unmatched {}",
  874.                "Unmatched ()",           "Missing",
  875.                "Not a function",         "Misplaced break",
  876.                "Out of place",           "Too many strings",
  877.                "Token buffer overflow",  "Divide by zero"    };
  878. static FILE *fp;
  879. void main(int argc, char *argv[])
  880. {
  881.     if (argc == 2)
  882.         if ((fp = fopen(argv[1], "r")) != NULL) {
  883.             loadsource();
  884.             fclose(fp);
  885.             interpret();
  886.         }
  887. }
  888. void sierror(enum errs erno, char *s, int line)
  889. {
  890.     printf("\r\n%s %s on line %d\n",s,erm[erno],line);
  891.     exit(1);
  892. }
  893. int getsource(void)     {   return getc(fp);    }
  894. void ungetsource(int c) {   ungetc(c, fp);      }
  895.